package io.renren.modules.sys.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.renren.common.exception.RRException;
import io.renren.common.utils.Result;
import io.renren.modules.sys.entity.PocketTemplateEntity;
import io.renren.modules.sys.entity.SysUserEntity;
import io.renren.modules.sys.service.PocketTemplateService;
import io.renren.modules.sys.utils.HomeUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;

import io.renren.modules.sys.dao.PocketDao;
import io.renren.modules.sys.entity.PocketEntity;
import io.renren.modules.sys.service.PocketService;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;


/**
 * @author Amadeus
 * @date 2020/12/04
 */
@Service("pocketService")
public class PocketServiceImpl extends ServiceImpl<PocketDao, PocketEntity> implements PocketService {

    @Autowired
    private PocketTemplateService pocketTemplateService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        IPage<PocketEntity> page = this.page(
                new Query<PocketEntity>().getPage(params),
                Wrappers.<PocketEntity>lambdaQuery()
                        .eq(PocketEntity::getCreateBy, user.getUsername())
        );
        return new PageUtils(page);
    }

    @Override
    @Transactional(rollbackFor = {RRException.class}, isolation = Isolation.READ_COMMITTED)
    public Result savePocket(PocketEntity pocket) {
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        pocket.setCreateBy(user.getUsername());
        this.save(pocket);
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = {RRException.class}, isolation = Isolation.READ_COMMITTED)
    public Result saveOrUpdatePocket(PocketEntity pocket) {
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        pocket.setUpdateBy(user.getUsername());
        this.saveOrUpdate(pocket);
        return Result.success();
    }

    @Override
    public Result getPocketList(Map<String, Object> params) {
        //获取当前用户信息
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        //获取搜索条件 若为空不拼接条件
        String key = (String) params.get("key");
        String startTime = (String) params.get("startTime");
        String endTime = (String) params.get("endTime");
        IPage<PocketEntity> page = this.page(
                new Query<PocketEntity>().getPage(params),
                Wrappers.<PocketEntity>lambdaQuery()
                        .eq(PocketEntity::getCreateBy, user.getUsername())
                        .and(StrUtil.isNotBlank(key), i -> i.eq(PocketEntity::getId, key)
                                .or(StrUtil.isNotBlank(key)).eq(PocketEntity::getPayment, key)
                                .or(StrUtil.isNotBlank(key)).like(PocketEntity::getReason, key)
                                .or(StrUtil.isNotBlank(key)).like(PocketEntity::getRemark, key))
                        .ge(StrUtil.isNotBlank(startTime), PocketEntity::getPaydata, startTime)
                        .le(StrUtil.isNotBlank(endTime), PocketEntity::getPaydata, endTime)
                        .orderByDesc(PocketEntity::getPaydata)
                        .orderByDesc(PocketEntity::getCreateTime)
        );
        return Result.success(page);
    }

    @Override
    public Result getPocketSumList() {
        //获取当前用户信息
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();

        JSONObject jsonObject = new JSONObject();
        Calendar cal = Calendar.getInstance();
        int month = cal.get(Calendar.MONTH);
        int year = cal.get(Calendar.YEAR);
        //如果当前为一月份 上个月则为上一年十二月
        if (cal.get(Calendar.MONTH) == Calendar.JANUARY) {
            month = Calendar.UNDECIMBER;
            year = cal.get(Calendar.YEAR) - 1;
        }
        //今日收入wrapper
        LambdaQueryWrapper<PocketEntity> todayIncomeWrapper = Wrappers.lambdaQuery(PocketEntity.class);
        HomeUtils.buildSelectWrapper(user, todayIncomeWrapper);
        //今日收入
        List<PocketEntity> todayIncomeList = this.list(todayIncomeWrapper
                //类型大于0的为支出数目
                .gt(PocketEntity::getType, 0)
                .eq(PocketEntity::getPaydata, LocalDateTime.of(
                        cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1,
                        cal.get(Calendar.DATE), 0, 0)));
        BigDecimal income = checkNull(todayIncomeList);

        //今日支出wrapper
        LambdaQueryWrapper<PocketEntity> todaySumWrapper = Wrappers.lambdaQuery(PocketEntity.class);
        HomeUtils.buildSelectWrapper(user, todaySumWrapper);
        HomeUtils.buildSumSelectWrapper(todaySumWrapper);
        //今日消费
        List<PocketEntity> todaySumList = this.list(todaySumWrapper
                .eq(PocketEntity::getPaydata, LocalDateTime.of(
                        cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1,
                        cal.get(Calendar.DATE), 0, 0)));

        BigDecimal todaySum = checkNull(todaySumList);

        //至今消费wrapper
        LambdaQueryWrapper<PocketEntity> sumWrapper = Wrappers.lambdaQuery(PocketEntity.class);
        HomeUtils.buildSelectWrapper(user, sumWrapper);
        HomeUtils.buildSumSelectWrapper(sumWrapper);
        //日均消费=至今总消费/记账日期数
        BigDecimal sum = this.list(sumWrapper)
                .stream()
                .map(PocketEntity::getPayment)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        long count = this.list(Wrappers.<PocketEntity>lambdaQuery()
                .eq(PocketEntity::getCreateBy, user.getUsername()))
                .stream()
                .map(PocketEntity::getPaydata)
                .distinct()
                .count();

        BigDecimal average = sum.divide(new BigDecimal(count), 2, RoundingMode.HALF_UP);
        //至今收入
        LambdaQueryWrapper<PocketEntity> incomeAllWrapper = Wrappers.lambdaQuery(PocketEntity.class);
        HomeUtils.buildSelectWrapper(user, incomeAllWrapper);
        HomeUtils.buildIncomeSelectWrapper(incomeAllWrapper);
        BigDecimal incomeAll = this.list(incomeAllWrapper)
                .stream()
                .map(PocketEntity::getPayment)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //本月总消费
        BigDecimal monthSum = this.list(sumWrapper
                .ge(PocketEntity::getPaydata, LocalDateTime.of(
                        cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1,
                        1, 0, 0))
                .le(PocketEntity::getPaydata, LocalDateTime.now()))
                .stream()
                .map(PocketEntity::getPayment)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        //上个月总消费
        BigDecimal lastMonthSum = this.list(Wrappers.<PocketEntity>lambdaQuery()
                .select(PocketEntity::getPayment)
                .eq(PocketEntity::getCreateBy, user.getUsername())
                .le(PocketEntity::getType, 0)
                .le(PocketEntity::getPaydata, LocalDateTime.of(
                        cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1,
                        1, 0, 0))
                .ge(PocketEntity::getPaydata, LocalDateTime.of(
                        year, month,
                        1, 0, 0)))
                .stream()
                .map(PocketEntity::getPayment)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //上个月总收入
        BigDecimal lastMonthIncome = this.list(Wrappers.<PocketEntity>lambdaQuery()
                .select(PocketEntity::getPayment)
                .eq(PocketEntity::getCreateBy, user.getUsername())
                .gt(PocketEntity::getType, 0)
                .le(PocketEntity::getPaydata, LocalDateTime.of(
                        cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1,
                        1, 0, 0))
                .ge(PocketEntity::getPaydata, LocalDateTime.of(
                        year, month,
                        1, 0, 0)))
                .stream()
                .map(PocketEntity::getPayment)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        jsonObject.put("income", income);
        jsonObject.put("pay", todaySum);
        jsonObject.put("dayPay", average);
        jsonObject.put("sum", monthSum);
        jsonObject.put("incomeAll", incomeAll.subtract(sum));
        jsonObject.put("lastMonthSum", lastMonthSum);
        jsonObject.put("lastMonthIncome", lastMonthIncome);
        jsonObject.put("lastMonthEarn", lastMonthIncome.subtract(lastMonthSum));
        if (todaySum.compareTo(average) > 0) {
            jsonObject.put("dayPayHeight", todaySum.subtract(average));
        } else {
            jsonObject.put("dayPayHeight", null);
        }
        return Result.success(jsonObject);
    }

    @Override
    public Result savePocketTemplate(List<Integer> ids) {
        SysUserEntity user = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
        //如果不传参数 则一键按模板添加全部
        List<PocketTemplateEntity> pocketTemplate;
        if (CollUtil.isEmpty(ids)) {
            pocketTemplate = this.pocketTemplateService.list();
        } else {
            pocketTemplate = this.pocketTemplateService.listByIds(ids);
        }

        List<PocketEntity> collect = pocketTemplate.stream().map(i -> {
            PocketEntity pocketEntity = new PocketEntity();
            BeanUtils.copyProperties(i, pocketEntity);
            pocketEntity.setPaydata(LocalDate.now());
            pocketEntity.setCreateBy(user.getUsername());
            return pocketEntity;
        }).collect(Collectors.toList());
        this.saveBatch(collect);
        return Result.success();
    }

    /**
     * 检查空 然后流处理结果
     *
     * @param list 列表
     * @return BigDecimal
     */
    private BigDecimal checkNull(List<PocketEntity> list) {
        if (CollUtil.isEmpty(list)) {
            return new BigDecimal(0);
        }

        return list.stream()
                .map(PocketEntity::getPayment)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

}